﻿using Vboot.Core.Module.Sys;
using DbType = SqlSugar.DbType;

namespace Vboot.Core.Module.Bpm;

[ApiDescriptionSettings("Bpm", Tag = "流程引擎-实例")]
public class BpmProcMainApi : IDynamicApiController
{
    private readonly BpmProcMainService _service;
    
    private readonly BpmTaskMainService _taskMainService;
    
    private readonly SysOrgRoleTreeService _sysOrgRoleTreeService;

    private readonly BpmProcMainHand _hand;

    public BpmProcMainApi(BpmProcMainService service,
        BpmProcMainHand hand,
        BpmTaskMainService taskMainService,
        SysOrgRoleTreeService sysOrgRoleTreeService)
    {
        _service = service;
        _hand = hand;
        _taskMainService = taskMainService;
        _sysOrgRoleTreeService = sysOrgRoleTreeService;
    }

    [QueryParameters]
    public async Task<dynamic> Get(string name)
    {
        var pp = XreqUtil.GetPp();
        var items = await _service.repo.Context.Queryable<BpmProcMain>()
            .WhereIF(!string.IsNullOrWhiteSpace(name), t => t.name.Contains(name.Trim()))
            .Select((t) => new {t.id, t.name})
            .ToPageListAsync(pp.page, pp.pageSize, pp.total);
        return RestPageResult.Build(pp.total.Value, items);
    }

    public async Task<BpmProcMain> GetOne(string id)
    {
        var cate = await _service.repo.Context.Queryable<BpmProcMain>()
            .Where(it => it.id == id).FirstAsync();
        return cate;
    }

    [QueryParameters]
    public async Task<Dictionary<string, object>> GetZbpm(string proid)
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();
        //审批记录
        string sql = "select t.id \"id\",t.crtim \"crtim\",t.facna \"facna\",t.facno \"facno\",t.opnot \"opnot\"," +
                     "t.opinf \"opinf\",o.name as \"haman\" from bpm_audit_main t " +
                     "inner join sys_org o on o.id=t.haman " +
                     "where t.proid=@proid order by t.crtim";
        List<dynamic> audits = await _service.repo.Context.Ado.SqlQueryAsync<dynamic>(sql, new {proid});
        dict.Add("audits", audits);

        //历史处理人
        string hiHamen = "";
        foreach (var audit in audits)
        {
            if (!hiHamen.Contains("" + audit.haman))
            {
                hiHamen += audit.haman + ";";
            }
        }

        if (hiHamen.Contains(";"))
        {
            hiHamen = hiHamen.Substring(0, hiHamen.Length - 1);
        }

        dict.Add("hiHamen", hiHamen);

        //当前处理人与当前用户是否在当前处理人中
        string sql2 =
            "select n.id as \"tasid\",t.id as \"nodid\",o.name \"exnam\",n.exman \"exman\",t.proid \"proid\"," +
            "t.facno \"facno\",t.facna \"facna\",n.type \"tasty\" from bpm_node_main t" +
            " inner join bpm_task_main n on n.nodid=t.id " +
            "inner join sys_org o on o.id=n.exman " +
            "where t.proid=@proid and n.actag=1 order by n.ornum";
        List<dynamic> tasks = await _service.repo.Context.Ado.SqlQueryAsync<dynamic>(sql2, new {proid});
        string cuExmen = "";
        bool cutag = false;
        string userId = XuserUtil.getUserId();
        string postSql = "select pid as id from sys_org_post_org where oid=@oid";
        List<string> postIdList = await _service.repo.Context.Ado.SqlQueryAsync<string>(postSql, new {oid=userId});

        Zbpm zbpm = new Zbpm();
        foreach (var task in tasks)
        {
            if (string.IsNullOrEmpty(zbpm.proid))
            {
                zbpm.proid = "" + task.proid;
                zbpm.nodid = "" + task.nodid;
                zbpm.facno = "" + task.facno;
                zbpm.facna = "" + task.facna;
            }

            cuExmen += task.exnam + ";";
            if (userId == "" + task.exman)
            {
                zbpm.tasid = "" + task.tasid;
                zbpm.tasty = "" + task.tasty;
                zbpm.exman = "" + task.exman;
                cutag = true;
            }
            if (!cutag) {
                foreach (var postId in postIdList)
                {
                    if (postId=="" + task.exman) {
                        zbpm.tasid = "" + task.tasid;
                        zbpm.tasty = "" + task.tasty;
                        zbpm.exman = "" + task.exman;
                        cutag = true;
                    }
                }
            }
        }

        if (cuExmen.Contains(";"))
        {
            cuExmen = cuExmen.Substring(0, cuExmen.Length - 1);
        }

        dict.Add("cuExmen", cuExmen);
        dict.Add("cutag", cutag);
        dict.Add("zbpm", zbpm);
        return dict;
    }

    //获取即将流向的节点
    [QueryParameters]
    public async Task<Dictionary<string, object>> GetTarget(string proid, string facno,string modty)
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();
        Znode nextNode;
        //如果是之前被驳回的节点则，通过后要判断是否直接返回驳回的节点
        string refuseSql = "select t.id \"id\",t.paval \"paval\" from bpm_proc_param t where t.proid=@proid and t.pakey=@pakey";
        dynamic bacMap =
            _service.repo.Context.Ado.SqlQuerySingle<dynamic>(refuseSql, new {proid, pakey = facno + "#refuse"});
        string xmlSql = @"select t.chxml from bpm_proc_tmpl t 
inner join bpm_proc_main m on m.tmpid=t.id  where m.id=@proid";
        string chxml = await _service.repo.Context.Ado.SqlQuerySingleAsync<string>(xmlSql, new {proid});
        if (bacMap != null && !string.IsNullOrEmpty(bacMap.paval))
        {
            nextNode = _hand.GetNodeInfo(chxml, "" + bacMap.paval);
        }
        else
        {
            List<BpmTaskMain> bpmTaskMainList = await _taskMainService.FindAllByProidNotActive(proid);
            if (bpmTaskMainList.Count > 0) {
                nextNode = _hand.GetNodeInfo(chxml, facno);
            } else {
                Zcond zcond=new Zcond();
                zcond.proid=proid;
                zcond.modty=modty;
                nextNode = _hand.CalcTarget(zcond,chxml, facno);
            }
        }
        
        string tamen = "暂时无法计算";
        if (nextNode == null)
        {
            nextNode = new Znode();
            nextNode.facno = "NX";
            nextNode.facna = "未知节点";
        }
        else
        {
            tamen =await calcTamen(nextNode.exmen);
        }
        // string sql = "select t.name as id from sys_org t where t.id=@exman";
        // string tamen = await _service.repo.Context.Ado.SqlQuerySingleAsync<string>(sql, new {exman = nextNode.exman});
        dict.Add("tarno", nextNode.facno);
        dict.Add("tarna", nextNode.facna);
        dict.Add("tamen", tamen);
        if (bacMap != null)
        {
            dict.Add("bacid", bacMap.id);
        }

        return dict;
    }

    [QueryParameters]
    public async Task<Dictionary<string, object>> GetXml(string proid)
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();
        string xmlSql =
            "select t.orxml from bpm_proc_tmpl t inner join bpm_proc_main m on m.tmpid=t.id where m.id=@proid";
        string xml = await _service.repo.Context.Ado.SqlQuerySingleAsync<string>(xmlSql, new {proid});

        //SqlServer异常 SELECT DISTINCT，那么 ORDER BY 子句中的项就必须出现在选择列表中。
        // string sql = "select distinct t.facno from bpm_node_hist t where t.proid=@proid order by t.sttim";
        string sql = "select distinct t.facno from bpm_node_hist t where t.proid=@proid";
        List<string> nodeList = await _service.repo.Context.Ado.SqlQueryAsync<string>(sql, new {proid});

        List<ZidNamePid> allLineList = _hand.GetAllLineList(xml);
        HashSet<string> lineSet = new HashSet<string>();
        foreach (var zinp in allLineList)
        {
            foreach (var node in nodeList)
            {
                if (zinp.name == node)
                {
                    foreach (var node2 in nodeList)
                    {
                        if (zinp.pid == node2)
                        {
                            lineSet.Add(zinp.id);
                            break;
                        }
                    }

                    break;
                }
            }
        }

        dict.Add("xml", xml);
        dict.Add("nodeList", nodeList);
        dict.Add("lineList", lineSet);
        return dict;
    }

    [QueryParameters]
    public async Task<Dictionary<string, object>> GetTexml(string tmpid)
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();
        string xmlSql = "select t.orxml from bpm_proc_tmpl t where t.id=@tmpid";
        string xml = await _service.repo.Context.Ado.SqlQuerySingleAsync<string>(xmlSql, new {tmpid});
        Znode nextNode = _hand.GetFirstNode(xml, "N1");
        string tamen = "暂时无法计算";
        if (nextNode == null)
        {
            nextNode = new Znode();
            nextNode.facno = "NX";
            nextNode.facna = "未知节点";
        }
        else
        {
            tamen =await calcTamen(nextNode.exmen);
        }
        // string tamenSql = "select t.name as id from sys_org t where t.id=@exman";
        // string tamen =
        //     await _service.repo.Context.Ado.SqlQuerySingleAsync<string>(tamenSql, new {exman = nextNode.exman});
        dict.Add("tarno", nextNode.facno);
        dict.Add("tarna", nextNode.facna);
        dict.Add("tamen", tamen);
        dict.Add("xml", xml);
        return dict;
    }

    public async Task PostHpass(Zbpm zbpm)
    {
        zbpm.haman = XuserUtil.getUserId();
        string sql = "select m.id \"proid\",m.name \"prona\" from bpm_proc_main m where m.id=@proid";
        dynamic map = await _service.repo.Context.Ado.SqlQuerySingleAsync<dynamic>(sql, new {proid = zbpm.proid});
        zbpm.prona = "" + map.prona;
        await _service.HandlerPass(zbpm);
    }

    public async Task PostHrefuse(Zbpm zbpm)
    {
        zbpm.haman = XuserUtil.getUserId();
        string sql = "select m.id \"proid\",m.name \"prona\" from bpm_proc_main m where m.id=?";
        dynamic map = await _service.repo.Context.Ado.SqlQuerySingleAsync<dynamic>(sql, new {proid = zbpm.proid});
        zbpm.prona = "" + map.prona;
        await _service.HandlerRefuse(zbpm);
    }

    //返回当前节点之前的已走过的节点
    [QueryParameters]
    public async Task<List<dynamic>> GetRefnodes(string proid, string facno)
    {
        string sql ="select distinct t.facno \"id\",t.facna \"name\",t.haman \"exman\",t.crtim " +
                    "from bpm_audit_main t where proid=@proid and opkey in('dsubmit','pass') order by t.crtim";
        List<dynamic> allList = await _service.repo.Context.Ado.SqlQueryAsync<dynamic>(sql, new {proid});
        List<dynamic> list = new List<dynamic>();
        foreach (var item in allList)
        {
            if (item.id == facno)
            {
                break;
            }

            list.Add(item);
        }

        return list;
    }
    
    private async Task<string> calcTamen(string exman) {
        var dbOptions = App.GetOptions<ConnectionStringsOptions>();

    
        string tamen = "";
        if ( !string.IsNullOrEmpty(exman) && !exman.Contains(";")) {
            string tamenSql = "select t.id, t.name,t.type from sys_org t where t.id=@id";
            
            SysOrg sysOrg= await _service.repo.Context.Ado.SqlQuerySingleAsync<SysOrg>(tamenSql,new {id=exman});
            if (sysOrg.type==32) {
                SysOrg org =await _sysOrgRoleTreeService.calc(XuserUtil.getUserId(), sysOrg.id);
                tamen = org.name;
            } else {
                tamen = sysOrg.name;
            }
        } else if (!string.IsNullOrEmpty(exman) && exman.Contains(";"))
        {
            string ids =  "'" + exman.Replace(";", "','") + "'";
            
            string sql2 = "select t.id,t.name,t.type from sys_org t where id in ("+ids+")";
            if (dbOptions.ConnectionConfigs[0].DbType == DbType.MySql)
            {
                sql2 += " order by field(id," + ids + ")";
            }else if (dbOptions.ConnectionConfigs[0].DbType == DbType.SqlServer)
            {
                sql2+=" order by CHARINDEX(id,'" + ids.Replace("'","") + "')";
            }else if (dbOptions.ConnectionConfigs[0].DbType == DbType.Oracle)
            {
                sql2+=" order by INSTR('" + ids.Replace("'","") + "',id)";
            }

            Console.WriteLine(sql2);
            List<SysOrg> list= await _service.repo.Context.Ado.SqlQueryAsync<SysOrg>(sql2);
            foreach (var sysOrg in list)
            {
                if (sysOrg.type == 32) {
                    SysOrg org =await _sysOrgRoleTreeService.calc(XuserUtil.getUserId(), sysOrg.id);
                    tamen += org.name + ";";
                } else {
                    tamen += sysOrg.name + ";";
                }
            }
            tamen = tamen.Substring(0, tamen.Length - 1);
        }
        return tamen;
    }

    public async Task Post(BpmProcMain main)
    {
        await _service.InsertAsync(main);
    }

    public async Task Put(BpmProcMain cate)
    {
        await _service.UpdateAsync(cate);
    }

    public async Task Delete(string ids)
    {
        await _service.DeleteAsync(ids);
    }
}